import gradio as gr 
from XEdu.LLM import Client 
import os 
import subprocess 
import tempfile 
import socket 
from datetime import datetime 
import webbrowser 
 
# 配置AI模型客户端 
chatbot = Client(provider='****',
               api_key='***********************************',
               model='***************') # 实例化客户端
 
# 获取当前时间戳 
def get_timestamp(): 
    return datetime.now().strftime("%Y%m%d_%H%M%S")  
 
# 安全执行生成的代码 
def execute_generated_code(code): 
    try: 
        # 创建临时文件保存代码 
        with tempfile.NamedTemporaryFile(suffix='.py', delete=False, mode='w', encoding='utf-8') as tmp: 
            tmp.write(code)  
            tmp_path = tmp.name   
 
        # 执行代码并捕获输出 
        result = subprocess.run(['python',   tmp_path], 
                              capture_output=True, 
                              text=True, 
                              timeout=1000) 
 
        # 清理临时文件 
        os.unlink(tmp_path)  
 
        if result.returncode   == 0: 
            return f"执行成功:\n{result.stdout}"  
        else: 
            return f"执行出错:\n{result.stderr}"  
 
    except subprocess.TimeoutExpired: 
        return "错误: 代码执行超时(超过1000秒)" 
    except Exception as e: 
        return f"执行时发生错误: {str(e)}" 
 
# 生成HTML可视化结果 
def generate_html_visualization(code, execution_result): 
    html_template = f""" 
    <!DOCTYPE html> 
    <html> 
    <head> 
        <title>代码执行结果可视化</title> 
        <style> 
            body {{ font-family: Arial, sans-serif; margin: 20px; }} 
            .container {{ display: flex; }} 
            .code-section {{ width: 45%; padding: 10px; background-color: #f5f5f5; }} 
            .result-section {{ width: 45%; padding: 10px; margin-left: 10px; }} 
            pre {{ background-color: #f0f0f0; padding: 10px; border-radius: 5px; }} 
            .visualization {{ margin-top: 20px; padding: 15px; background-color: #e9f7fe; border-radius: 5px; }} 
        </style> 
    </head> 
    <body> 
        <h1>代码执行结果可视化</h1> 
        <div class="container"> 
            <div class="code-section"> 
                <h2>生成的代码</h2> 
                <pre>{code}</pre> 
            </div> 
            <div class="result-section"> 
                <h2>执行结果</h2> 
                <pre>{execution_result}</pre> 
            </div> 
        </div> 
        <div class="visualization"> 
            <h2>可视化效果</h2> 
            <div id="visualization-area"> 
                <!-- 这里将显示可视化内容 --> 
                {get_visualization_content(code, execution_result)} 
            </div> 
        </div> 
    </body> 
    </html> 
    """ 
    return html_template 
 
def get_visualization_content(code, execution_result): 
    # 根据代码类型生成不同的可视化内容 
    if "turtle" in code: 
        return "<p>图形绘制结果已显示在独立窗口中</p>" 
    elif "matplotlib" in code: 
        return "<img src='generated_plot.png'   alt='生成的图表'>" 
    else: 
        return f"<pre>{execution_result}</pre>" 
 
# 清理代码，删除头尾的 ```python``` 
def clean_code(code): 
    if code.startswith("```python")  and code.endswith("```"):  
        code = code[9:-3].strip() 
    return code 
 
# 处理用户需求 
def process_request(user_prompt): 
    try: 
        # 生成代码提示 
        code_prompt = f"""请根据以下需求生成完整的Python代码: 
{user_prompt} 
 
要求: 
1. 只生成可执行的Python代码
2. 只返回纯代码，不要包含任何Markdown标记(如```python```)
3. 代码必须完整独立可运行 
4. 如果涉及图形绘制，使用turtle库 
5. 代码最后要调用main()或相关函数 
""" 
        # 调用AI生成代码 
        generated_code = chatbot.inference(code_prompt)  
        
        # 清理代码 
        generated_code = clean_code(generated_code) 
 
        # 执行生成的代码 
        execution_result = execute_generated_code(generated_code) 
 
        # 生成HTML可视化 
        html_output = generate_html_visualization(generated_code, execution_result) 
 
        # 保存HTML文件 
        output_file = f"output_{get_timestamp()}.html" 
        with open(output_file, "w", encoding="utf-8") as f: 
            f.write(html_output)  
 
        # 在浏览器中打开结果 
        webbrowser.open(f"file://{os.path.abspath(output_file)}")  
 
        return generated_code, execution_result, output_file 
 
    except Exception as e: 
        return f"生成代码时出错: {str(e)}", "", "" 
 
# 创建Gradio界面 
with gr.Blocks(title="AI代码生成执行系统") as demo: 
    gr.Markdown("## AI代码生成与执行系统") 
    gr.Markdown("输入您的需求，AI将自动生成并执行对应的Python代码，并在网页中显示结果") 
 
    with gr.Row(): 
        user_input = gr.Textbox(label="请输入您的代码需求", 
        placeholder="例如: 请画一个红色的三角形", lines=10)

    with gr.Row(): 
        submit_btn = gr.Button("生成并执行代码")

    with gr.Row(): 
        code_output = gr.Code(label="生成的代码", language="python")

    with gr.Row(): 
        exec_output = gr.Textbox(label="执行结果", lines=5)

    with gr.Row(): 
        html_output = gr.File(label="可视化结果", visible=False) 
 
    # 记录功能 
    with gr.Accordion("高级选项", open=False): 
        session_id = gr.Textbox(label="会话ID(可选)", 
                              value=f"session_{socket.gethostname()}_{get_timestamp()}")  
        log_checkbox = gr.Checkbox(label="记录本次会话", value=True) 
 
    # 处理函数 
    def process_and_display(user_prompt, session_id, do_logging): 
        code, result, html_file = process_request(user_prompt) 
 
        # 记录日志 
        if do_logging: 
            log_dir = "code_gen_logs" 
            os.makedirs(log_dir,   exist_ok=True) 
            log_file = os.path.join(log_dir,   f"{session_id}.txt") 
            with open(log_file, "a", encoding="utf-8") as f: 
                f.write(f"  时间: {datetime.now()}\n")  
                f.write(f"  需求: {user_prompt}\n") 
                f.write(f"  生成的代码:\n{code}\n") 
                f.write(f"  执行结果:\n{result}\n") 
                f.write("="*50   + "\n") 
 
        return code, result, html_file if html_file else None 
 
    # 绑定事件 
    submit_btn.click(  
        fn=process_and_display, 
        inputs=[user_input, session_id, log_checkbox], 
        outputs=[code_output, exec_output, html_output] 
    ) 
 
# 启动应用 
if __name__ == "__main__": 
    demo.launch(server_name="127.0.0.1",   server_port=7860, share=False) 
